
#include "apdu_lib_pin_mgr.h"
#include "apdu_lib_common.h"

#include "../apdu.core/apdu.h"

#include "../../mk_lib/mk_auto_ptr.h"
#include "../../mk_lib/mk_utility.h"

#include <stdlib.h>
#include <string.h>
#include "../apdu.algo/mac.h"
#include "../apdu.algo/sm4.h"


#include "../../mk_lib/mk_logger.h"

extern int	g_sw;

int app_get_pin_info( HANDLE devHandle, int pin_type, int app_id, 
					 int * max_retry, int * left_times, int * state )
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_dev_mgr()->create_apdu_get_pin_info(pin_type, app_id);
	newApdu->set_le(3);

	mk_auto_ptr<apdu> ap(newApdu);
	
	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len;
	unsigned char * pData = newApdu->get_response_data(&data_len);
	if(data_len < 3)
	{
		return 3;
	}

	* max_retry = pData[0];
	* left_times = pData[1];
	* state = pData[2];


	return 0;
}

int app_change_pin( HANDLE devHandle, unsigned char random[16], 
				   int pin_type, int app_id, char * old_pin, char * new_pin )
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_dev_mgr()->create_apdu_change_pin(random, pin_type, app_id, old_pin, new_pin);
	
	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;

}

int app_verify_pin( HANDLE devHandle, unsigned char random[16], 
				   int pin_type, int app_id, char * pin )
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_dev_mgr()->create_apdu_verify_pin(random, pin_type, app_id, pin);

	mk_auto_ptr<apdu> ap(newApdu);
	
	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}

int app_unblock_pin( HANDLE devHandle, unsigned char random[16], int app_id,
					char * admin_pin, char * user_pin )
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_dev_mgr()->create_apdu_unblock_pin(random, app_id, admin_pin, user_pin);

	mk_auto_ptr<apdu> ap(newApdu);

	
	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;

}

int app_reload_pin(HANDLE devHandle, unsigned char random[16], 
				   int app_id, char * user_pin)
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_dev_mgr()->create_apdu_reload_pin(random, app_id, user_pin);

	mk_auto_ptr<apdu> ap(newApdu);


	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}

int app_remote_unblock_pin( HANDLE devHandle, int app_id, unsigned char cipher[20], int cipher_len)
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_dev_mgr()->create_apdu_remote_unblock_pin(app_id, cipher, cipher_len);

	mk_auto_ptr<apdu> ap(newApdu);


	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;

}

int app_clear_secure_state( HANDLE devHandle, int app_id )
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_dev_mgr()->create_apdu_clear_secure_state(app_id);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}


int app_clear_secure_state_ex( HANDLE devHandle, int app_id, int mode )
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_dev_mgr()->create_apdu_clear_secure_state_ex(app_id, mode);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}

int app_verify_pin_ms(HANDLE devHandle, int app_id, int pin_type, unsigned char * acknowlege, int ack_len)
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_dev_mgr()->create_apdu_verify_pin_ms(pin_type, app_id, acknowlege, ack_len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}

int app_unblock_pin_ms(HANDLE devHandle, int app_id,unsigned char * acknowlege, int ack_len, char * user_pin)
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_dev_mgr()->create_apdu_unblock_pin_ms(app_id, acknowlege, ack_len, user_pin);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}

int app_change_pin_ms( HANDLE devHandle, int app_id, int pin_type, 
					  unsigned char * acknowlege, int ack_len, unsigned char * new_pin, int new_pin_len)
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_dev_mgr()->create_apdu_change_pin_ms(pin_type, app_id, acknowlege, ack_len, new_pin, new_pin_len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}


unsigned char* app_sm_encrypt(unsigned char key[16], unsigned char * input, int input_len, int * out_len )
{
	int pad_len = 16;
	int new_len = 0;
	unsigned char * out_buff = NULL;

	new_len = input_len + 2; // fill 2 bytes length
	new_len = ((new_len / pad_len) + 1) * pad_len; //get final length

	out_buff = (unsigned char*)malloc(new_len);
	memset(out_buff,0, new_len);

	int pos = 0;
	memcpy(out_buff, &input_len, 2);
	pos += 2;

	memcpy(out_buff + pos, input, input_len);
	pos += input_len;

	out_buff[pos] = 0x80;

	sm4_ecb(key, out_buff, new_len, SM4_ENCRYPT);

	* out_len = new_len;

	return out_buff;
}
